<template>
  <div>
    <input type="file" @change="handleFileChange" />
    <el-button type="primary" @click="handleUpload">上传</el-button>
    <!-- <el-button @click="handlePaused">{{pausedRef ? '继续':'暂停'}}</el-button> -->
    <el-progress :percentage="percentageRef" />
  </div>
</template>
<script setup name="Photos">
import { ref , onBeforeUnmount } from 'vue';
import {
  uploadChunkApi,
  verifyFileApi,
  mergeFileApi,
} from '../../apis/uploadApi';
import SparkmD5 from 'spark-md5';

const percentageRef = ref(0);

const fileRef = ref();
const fileHashRef = ref();
const pausedRef = ref(false); // 暂停

const CHUNK_SIZE = 1024 * 1024; // 分片大小
// 分片
const chunksList = (file) => {
  return new Promise((resolve, reject) => {
    const fileSize = file.size; // 文件大小
    const chunksCount = Math.ceil(fileSize / CHUNK_SIZE); // 分片总数

    const fileChunks = []; // 文件分片数
    // 处理分片
    for (let i = 0; i < chunksCount; i++) {
      const start = i * CHUNK_SIZE; // 起始点
      const end = i === chunksCount - 1 ? fileSize : start + CHUNK_SIZE; // 结束点
      const chunk = file.slice(start, end); // file 自带切片方法（同数组方法一样，起始点和结束点两个参数）
      fileChunks.push(chunk);
    }
    resolve(fileChunks);
  });
};

// md5 hash 文件唯一标识
const fileHash = (chunks) => {
  return new Promise((resolve, rejeact) => {
    const spark = new SparkmD5();

    // 递归读取文件内容
    function _read(i) {
      if (i >= chunks.length) {
        resolve(spark.end());
        return;
      }
      // 文件
      const blob = chunks[i];
      // 创建blob文件读取
      const reader = new FileReader();
      reader.onload = (e) => {
        const byts = e.target.result;

        spark.append(byts);

        _read(i + 1);
      };
      reader.readAsArrayBuffer(blob);
    }
    _read(0);
  });
};

// 选择上传文件
const handleFileChange = (e) => {
  fileRef.value = e.target.files[0];
};



const confirmUpload = async () => {
  const file = fileRef.value;

  const fileChunks = await chunksList(file);
  fileHashRef.value = await fileHash(fileChunks);

  // 校验文件、分片文件是否存在
  const {
    data: { existFile, existChunks },
  } = await verify(fileHashRef.value);
  if (existFile) return;

  uploadChunk(fileChunks, existChunks);
}

// 上传文件
const uploadChunk = async (chunks, existChunks) => {
  const formDatas = chunks
    .map((chunk, index) => ({
      fileHash: fileHashRef.value,
      chunkHash: fileHashRef.value + '-' + index,
      chunk,
    }))
    .filter((item) => {
      // 过滤服务器已存在的切片
      return !existChunks.includes(item.chunkHash);
    })
    .map((item) => {
      const formData = new FormData();
      formData.append('file', item.chunk);
      formData.append('fileHash', item.fileHash);
      formData.append('chunkHash', item.chunkHash);
      return formData;
    });

  const taskPool = formDatas.map(
    (formDataItem) => (index) =>
      uploadChunkApi(formDataItem, (data) => {
        // // 暂停之后不再计算进度条
        // if (pausedRef.value) return;

        const fileSize = fileRef.value.size;
        const loaded = data.loaded;
        const existSize = existChunks.length * CHUNK_SIZE;
        const start = existSize + index * CHUNK_SIZE;
        const result = Number((Math.min(fileSize,  start + loaded) / fileSize) * 100);
        // 上传进度
        percentageRef.value = Math.round(result * 100) / 100 > 100 ? 100 : Math.round(result * 100) / 100;
        console.log(percentageRef.value)
      })
  );

  try {
    // 控制请求并发
    const res = await concurRequest(taskPool);
    // 合并请求
    mergeRequest();
  } catch (error) {

  }
};

// 控制请求并发
const concurRequest = (taskPool) => {
  return new Promise((resolve, reject) => {
    if (taskPool.length === 0) {
      resolve([]);
      return;
    }

    const results = [];
    let index = 0;
    let count = 0;

    const request = async () => {
      if (index === taskPool.length) return;
      if (pausedRef.value)  return;
      const i = index;
      const task = taskPool[index];
      index++;
      try {
        results[i] = await task(i);
      } catch (err) {
        results[i] = err;
        reject(err);
      } finally {
        count++;
        if (count === taskPool.length) {
          percentageRef.value = 100;
          resolve(results);
        }
        request();
      }
    };
    request();
  });
};

// 文件合并请求方法
const mergeRequest = async () => {
  await mergeFileApi({
    fileHash: fileHashRef.value,
    fileName: fileRef.value.name,
  });
};

// 检测文件是否存在方法
const verify = async (fileHash) => {
  return await verifyFileApi({ fileHash, fileName: fileRef.value.name });
};

// 确认上传(按钮)
const handleUpload = async () => {
  confirmUpload();
};

// 暂停、继续
const handlePaused = () => {
  if (!pausedRef.value) {
    pausedRef.value = true;
    return
  };
  pausedRef.value = false;
  confirmUpload();
}
onBeforeUnmount(() => {
  handlePaused();
})
</script>
